package loadbalance

import (
	"errors"
	"math/rand"
	"sync"
)

type EndpointPool struct {
	sync.Mutex
	inited      bool
	eps         []*Endpoint
	totalWeight int
	curWeights  []int // for round-robin
}

func (p *EndpointPool) AddEndpoint(ep *Endpoint) {
	p.Lock()
	defer p.Unlock()
	if p.inited {
		panic("cannot add ep to inited pool")
	}
	p.eps = append(p.eps, ep)
}

func (p *EndpointPool) PickServerByRoundRobin() (*Endpoint, error) {
	p.Lock()
	defer p.Unlock()
	return nextRoundRobinServer(p)
}

//func (p *Endpoint) PickServerByCHash(hashKey string) (*Endpoint, error) {
//	p.Lock()
//	defer p.Unlock()
//	return nextCHashServer(p)
//}

// RandomPick 不做任何检查, 随机挑选.
func (p *EndpointPool) RandomPick() (*Endpoint, error) {
	selectWeight := rand.Intn(10000) * p.totalWeight
	curWeight := 0

	p.Lock()
	defer p.Unlock()

	if !p.inited {
		panic("the endpoint pool no inited")
	}

	for _, v := range p.eps {
		curWeight += v.Weight * 10000
		if curWeight > selectWeight {
			return v, nil
		}
	}

	return nil, errors.New("no avaliable endpoint")
}

func (p *EndpointPool) Init() {
	p.Lock()
	defer p.Unlock()
	if p.inited {
		panic("the endpoint pool already inited")
	}
	p.curWeights = make([]int, len(p.eps))
	for _, v := range p.eps {
		p.totalWeight += v.Weight
	}
	p.inited = true
}

func NewEndpointPool() *EndpointPool {
	return &EndpointPool{
		eps: make([]*Endpoint, 0, 8),
	}
}
